package com.reeygu.base;

import com.reeygu.base.entity.*;

import java.util.Date;
import java.util.Scanner;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 测试一些常用的线程基础功能
 */
public class demo {
    /**
     * 主方法，选择和测试不同的用例方法
     * @param args
     */
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("Please enter the execution number:");
        int select = scanner.nextInt();
        switch (select) {
            //使用 Lock 实现手动锁，比 Synchronized 更强大
            case 1: lockDemo(); break;
            //使用 Synchronized 实现自动上锁
            case 2: synchronizedDemo(); break;
            //使用 Synchronized 实现单线程间通讯
            case 3: communicationSynchronized(); break;
            //使用 Synchronized 实现多线程间通讯，出现异常，需要使用while避免虚假唤醒
            case 4: communicationSynchronizedS(); break;
            //使用 Lock 实现单线程间通讯
            case 5: communicationLock(); break;
            //使用 Lock 实现线程间的 '定制化' 通讯
            case 6: customizationCommunicationLock(); break;
            //Synchronized 可重入锁
            case 7: reentrantSynchronized(); break;
            //Lock 可重入锁
            case 8: reentrantLock(); break;
            //死锁
            case 9: deadLock(); break;
            //Callable 实现更高级的线程锁
            case 10: callableDemo(); break;
            default:
                System.out.println("error!");
        }

    }

    /**
     * 使用 Synchronized 实现自动上锁
     * 出现异常自动释放锁，全自动
     */
    public static void synchronizedDemo() {
        SaleTicket saleTicket = new SaleTicket();
        //创建3个线程同时抢票
        new Thread( () -> {
            //执行买票操作
            for (int i = 0; i < 400; i++) {
                saleTicket.sale();
            }
            //此处的start不一定会让线程马上创建，而是由操作系统决定
        }, "A1").start();
        new Thread( () -> {
            //执行买票操作
            for (int i = 0; i < 400; i++) {
                saleTicket.sale();
            }
        }, "A2").start();
        new Thread( () -> {
            //执行买票操作
            for (int i = 0; i < 400; i++) {
                saleTicket.sale();
            }
        }, "A3").start();
    }

    /**
     * Lock 比 Synchronized 更强大，手动锁
     * 注意： Lock 不是java内置的，他是一个类，而Synchronized是java提供的关键字
     */
    public static void lockDemo() {
        LSaleTicket lSaleTicket = new LSaleTicket();
        //创建3个线程同时抢票
        new Thread( () -> {
            //执行买票操作
            for (int i = 0; i < 1400; i++) {
                lSaleTicket.saleB();
            }
        }, "A1").start();
        new Thread( () -> {
            //执行买票操作
            for (int i = 0; i < 1400; i++) {
                lSaleTicket.saleB();
            }
        }, "A2").start();
        new Thread( () -> {
            //执行买票操作
            for (int i = 0; i < 1400; i++) {
                lSaleTicket.saleB();
            }
        }, "A3").start();
    }

    public static void communicationSynchronized() {
        Share share = new Share();
        //负责+1
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A1").start();
        //负责-1
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A2").start();
    }

    /**
     * 同个方法多个线程调用出现的虚假唤醒，需要使用 while 环绕 wait()
     */
    public static void communicationSynchronizedS() {
        //Share share = new Share();
        ShareS share = new ShareS();
        //负责+1
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A1").start();
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B1").start();
        //负责-1
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A2").start();
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B2").start();
    }

    /**
     * 使用 Lock 实现手动上锁解锁的通讯案例
     */
    public static void communicationLock() {
        LockShare share = new LockShare();
        //负责+1
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A1").start();
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B1").start();
        //负责-1
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A2").start();
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B2").start();
    }

    private static void customizationCommunicationLock() {
        ShareResource share = new ShareResource();
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.returnA();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.returnB();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
        //负责-1
        new Thread( () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    share.returnC();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
    }

    /**
     * synchronized 的可重入锁案例
     * 可重入锁可以解锁自己本身的锁在内部随意调用
     */
    private static void reentrantSynchronized() {
        Object obj = new Object();
        new Thread( () -> {
            synchronized (obj) {
                System.out.println(Thread.currentThread().getName() + "::外层");
                synchronized (obj) {
                    System.out.println(Thread.currentThread().getName() + "::中层");
                    synchronized (obj) {
                        System.out.println(Thread.currentThread().getName() + "::内层");
                    }
                }
            }
        }, "reentrantLock").start();
    }

    /**
     *  可重入锁可以由内部调用它本身
     */
    private synchronized void add() {
        add();
    }

    /**
     * Lock 的可重入锁案例
     * 可重入锁可以解锁自己本身的锁在内部随意调用
     */
    private static void reentrantLock() {
        Lock lock = new ReentrantLock(true);
        new Thread( () -> {
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "::" + "外层");
                try {
                    lock.lock();
                    System.out.println(Thread.currentThread().getName() + "::" + "内层");
                } finally {
                    // 注意，上锁跟解锁是要配对的，否则会导致该锁一直被占用，
                    // 后面调用该锁的线程将无法正常作业
                    // * lock.unlock();
                }
            } finally {
                lock.unlock();
            }
        }, "reentrantLock").start();

        new Thread( () -> {
            lock.lock();
            System.out.println("由于*位置没有释放锁，所以此处会一直等待，无法到达");
            lock.unlock();
        }, "reentrantLock").start();
    }

    /**
     * 死锁示例
     */
    public static void deadLock() {
        //创建两个竞争者
        Object objA = new Object();
        Object objB = new Object();

        new Thread( () -> {
            synchronized (objA) {
                System.out.println("已上锁A， 但需要B资源才能解锁A，当前未解锁");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (objB) {
                    System.out.println("试图获取B锁，但可能被其他线程一直占用");
                }
            }
            System.out.println("已解锁A");
        }, "A").start();

        new Thread( () -> {
            synchronized (objB) {
                System.out.println("已上锁B， 但需要A资源才能解锁A，当前未解锁");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (objA) {
                    System.out.println("试图获取A锁，但可能被其他线程一直占用");
                }
            }
            System.out.println("已解锁B");
        }, "B").start();
    }

    public static void callableDemo() {
        //返回对象
        class Result {
            private int code;
            private String message;
            private Object data;
            public int getCode() {return code;}
            public void setCode(int code) {this.code = code;}
            public String getMessage() {return message;}
            public void setMessage(String message) {this.message = message;}
            public Object getData() {return data;}
            public void setData(Object data) {this.data = data;}
        }

        class myThreadCallable implements Callable {
            @Override
            public Object call() throws Exception {
                System.out.println("Runnable被使用");
                Result result = new Result();
                result.setCode(200);
                result.setMessage("请求成功");
                result.setData("1");
                return result;
            }
        }

        class myThreadRunnable implements Runnable {
            @Override
            public void run() {
                System.out.println("Runnable被使用");
            }
        }
        //创建 Runnable 线程
        new Thread(new myThreadRunnable(), "myRunnable").start();
        //创建 Callable 线程，则需要使用 FutureTask 封装
        FutureTask<Result> futureTask = new FutureTask<>(new myThreadCallable());
        //因为 Callable 是有 @FunctionalInterface 注解的，所以也可以通过 lambda 表达式简化代码
        FutureTask<Result> futureTaskLambda = new FutureTask<>(Result::new);
        new Thread(futureTask, "myCallable").start();
        //判断是否完成任务
        while (!futureTask.isDone()) {
            System.out.println("wait...");
        }
        //获取线程回调结果
        try {
            System.out.println(Thread.currentThread().getName() + "::" + futureTask.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

    /**
     * 辅助类：计数器
     * 业务：需要所有同学离开后，班长才能锁门，不能提前锁（该方法是错误示范）
     */
    public static void classDemo() {
        for (int i = 0; i < 6; i++) {
            new Thread( () -> {
                System.out.println(Thread.currentThread().getName() + "号同学离开了教室");
            }, String.valueOf(i)).start();
        }
        System.out.println("班长锁门");
    }

    /**
     * 减少计数
     * 使用 CountDownLatch 计数器优化上面方法后解决问题
     */
    public static void classCountDownLatchDemo() throws InterruptedException {
        //基数
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 0; i < 6; i++) {
            new Thread( () -> {
                System.out.println(Thread.currentThread().getName() + "号同学离开了教室");
                //计数器-1操作
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }
        //等待计算器为0时才放行
        countDownLatch.await();
        System.out.println("班长锁门");
    }

    private static  final int NUMBER = 6;
    /**
     * 循环栅栏
     * 使用 实现数据汇总后再执行任务，其实跟CountDownLatch的用法差不多，只不过这里是以任务次数的形式
     */
    public static void cyclicBarrierDemo() {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
            System.out.println("当等待次数与NUMBER相等时，才会执行该方法");
        });
        //调用6个业务
        for (int i = 0; i < 6; i++) {
            new Thread( () -> {
                try {
                    System.out.println(Thread.currentThread().getName() + "::完成任务");
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }

    /**
     * 信号灯
     */



}
